// AmfObject.cpp: implementation of the AmfObject class.
//
//////////////////////////////////////////////////////////////////////

//#include "stdafx.h"
#include "amf_object.h"
#include "./zlib/zlib.h"
#include "basic.h"
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
namespace Amf {
	OBJ_REGISTER_ABSTRACT(AmfIterator)
	OBJ_REGISTER(AmfObject)
	OBJ_REGISTER(AmfInt)
	OBJ_REGISTER(AmfDouble)
	OBJ_REGISTER(AmfString)
	OBJ_REGISTER(AmfBool)
	OBJ_REGISTER(AmfByteArray)
	OBJ_REGISTER(AmfArray)
	OBJ_REGISTER(AmfMap)
	OBJ_REGISTER(AmfAsObject)
	OBJ_REGISTER(AmfDate)
	OBJ_REGISTER(AmfExArrayInt)
	OBJ_REGISTER(AmfExArrayFloat64)

	/************************************************************************/
	/* AmfNull
	/************************************************************************/
	class AmfNull : public AmfObject
	{
	public:
		virtual int32 DataType()
		{
			return AMF3_UNDEFINED;
		}
		virtual int32 GetChildNumber() { throw HT::Except(HT_AMF_NULL_OBJ, "NULL Object"); }
		virtual int32 ToInt () { throw HT::Except(HT_AMF_NULL_OBJ, "NULL Object"); }
		virtual double ToDouble () {  throw HT::Except(HT_AMF_NULL_OBJ, "NULL Object"); }
		virtual wstring ToString () {  throw HT::Except(HT_AMF_NULL_OBJ, "NULL Object"); }
		virtual AmfObjectPtr Item (int i) {  throw HT::Except(HT_AMF_NULL_OBJ, "NULL Object"); }
		virtual AmfObjectPtr Item (const wchar_t* str) {  throw HT::Except(HT_AMF_NULL_OBJ, "NULL Object"); }
		static AmfObjectPtr Obj;
	};

	// static value
	AmfObjectPtr AmfNull::Obj = new AmfNull();
	/************************************************************************/
	/* AmfNullIterator
	/************************************************************************/
	class AmfNullIterator : public AmfIterator
	{
	public:
		virtual void MoveFirst () { throw HT::Except(HT_AMF_NO_CHILDREN, "NO Children"); }
		virtual void MoveNext () { throw HT::Except(HT_AMF_NO_CHILDREN, "NO Children"); }
		virtual bool Eof () { return true; }
		virtual bool Bof () { return true; }
		virtual AmfObjectPtr Get () { throw HT::Except(HT_AMF_NO_CHILDREN, "NO Children"); }
		virtual wstring GetKey () { throw HT::Except(HT_AMF_NO_CHILDREN, "NO Children"); }
		static AmfIteratorPtr Iterator;
	};

	// static value
	AmfIteratorPtr AmfNullIterator::Iterator = new AmfNullIterator;

	/************************************************************************/
	/* AmfObject
	/************************************************************************/
	AmfObjectPtr AmfObject::GetNullObject()
	{
		return AmfNull::Obj;
	}

	// 默认 Iterator
	AmfIteratorPtr AmfObject::GetChildIterator()
	{
		return AmfNullIterator::Iterator;
	}
	/************************************************************************/
	/* Global functions
	/************************************************************************/
#ifdef _WIN32
	extern wstring AToW (const char* pStrA)
	{
		unsigned int len = strlen(pStrA) + 1;
		wchar_t* pBuffer = new wchar_t[len];
		MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED,pStrA, -1, pBuffer, len);
		wstring w = pBuffer;
		delete pBuffer;
		return w;
	}
	extern string WToA (const wchar_t* pStrW)
	{
		unsigned int len = wcslen(pStrW)*2 + 1;
		char* pBuffer = new char[len];
		WideCharToMultiByte(CP_ACP,WC_NO_BEST_FIT_CHARS,pStrW,-1,pBuffer,len,NULL,NULL);
		string a = pBuffer;
		delete pBuffer;
		return a;
	}
#else
	extern wstring AToW (LPCTSTR pStrA)
	{
		wstring ret;
		int len = strlen(pStrA);
		wchar_t* pbuf = new wchar_t[len+1];
		swprintf(pbuf, len+1, L"%hs", pStrA);

		ret = pbuf;
		delete pbuf;

		return ret;
	}

	extern string WToA (const wchar_t* pStrW)
	{
		string ret;
		int len = wcslen(pStrW);
		char* pbuf = new char[len*2+1];
		sprintf (pbuf, "%ls", pStrW);

		ret = pbuf;
		delete pbuf;

		return ret;
	}
#endif // _WIN32

	extern string WToU8(const wchar_t* s, int32 len)
	{
		int32 inLen = (len > 0) ? len : wcslen(s);
		int32 c, count = 0;

 		const wchar_t * charr = s;
		string bytearr;
		bytearr.resize(inLen * 3);
		for (int32 i = 0; i < inLen; i++)
		{
			c = charr[i];
			if (c <= 0x007F)
			{
				bytearr[count++] = (byte)c;
			}
			else if (c > 0x07FF)
			{
				bytearr[count++] = (byte)(0xE0 | ((c >> 12) & 0x0F));
				bytearr[count++] = (byte)(0x80 | ((c >> 6) & 0x3F));
				bytearr[count++] = (byte)(0x80 | ((c >> 0) & 0x3F));
			}
			else
			{
				bytearr[count++] = (byte)(0xC0 | ((c >> 6) & 0x1F));
				bytearr[count++] = (byte)(0x80 | ((c >> 0) & 0x3F));
			}
		}
		bytearr.resize(count);

		return bytearr;
	}

	extern wstring U8ToW(const char * pStr, int32 len)
	{
		wstring charr;
		const char *bytearr = pStr;
		int utflen = (len > 0) ? len : strlen (pStr);
		charr.resize(utflen);

		int32 c, char2, char3;
		int32 count = 0;
		int32 chCount = 0;

		while (count < utflen)
		{
			c = (int32)bytearr[count] & 0xff;
			switch (c >> 4)
			{
			case 0:
			case 1:
			case 2:
			case 3:
			case 4:
			case 5:
			case 6:
			case 7:
				/* 0xxxxxxx*/
				count++;
				charr[chCount] = (wchar_t)c;
				break;
			case 12:
			case 13:
				/* 110x xxxx   10xx xxxx*/
				count += 2;
				if (count > utflen)
					//throw new UTFDataFormatException();
					return L"";

				char2 = (int32)bytearr[count - 1];
				if ((char2 & 0xC0) != 0x80)
					//throw new UTFDataFormatException();
					return L"";

				charr[chCount] = (wchar_t)(((c & 0x1F) << 6) | (char2 & 0x3F));
				break;
			case 14:
				/* 1110 xxxx  10xx xxxx  10xx xxxx */
				count += 3;
				if (count > utflen)
					//throw new UTFDataFormatException();
					return L"";

				char2 = (int32)bytearr[count - 2];
				char3 = (int32)bytearr[count - 1];
				if (((char2 & 0xC0) != 0x80) || ((char3 & 0xC0) != 0x80))
					//throw new UTFDataFormatException();
					return L"";

				charr[chCount] = (wchar_t)
					(((c & 0x0F) << 12) |
					((char2 & 0x3F) << 6) |
					((char3 & 0x3F) << 0));
				break;
			default:
				/* 10xx xxxx,  1111 xxxx */
				//throw new UTFDataFormatException();
				charr.resize(chCount);
				return charr;
			}

			chCount++;
		}

		charr.resize(chCount);

		return charr;
	}

	extern string WToU8(const wstring& StrW)
	{
		return WToU8(StrW.c_str());
	}

	extern wstring U8ToW(const string& StrW)
	{
		return U8ToW(StrW.c_str());
	}

	extern wstring AToW (const string& StrA)
	{
		return AToW(StrA.c_str());
	}

	extern string WToA (const wstring& StrW)
	{
		return WToA(StrW.c_str());
	}

	/************************************************************************/
	/* AmfArray
	/************************************************************************/
	template<class StdArrayClass, class ValueClass>
	class AmfArrayIterator : public AmfIterator
	{
		typedef typename StdArrayClass::iterator ItType;
		AmfObjectPtr pObj;	// parent
		StdArrayClass* pArray;
		ItType it;

	public:
		void Set (AmfObjectPtr parent, StdArrayClass* pArrayPtr)
		{
			pObj = parent;
			pArray = pArrayPtr;
			it = pArray->begin();
		}

		virtual void MoveFirst () { it = pArray->begin(); }
		virtual void MoveNext () { it++; }
		virtual bool Eof () { return (it == pArray->end()); }
		virtual AmfObjectPtr Get ()
		{
			if (it != pArray->end())
				return ToAmf(*it);
			else
				throw HT::Except (HT_AMF_EOF, "Is Eof");
			//return AmfObject::GetNull();
			return NULL;
		}

		virtual wstring GetKey ()
		{
			wstringstream buf;
			buf << (int32)(it - pArray->begin());
			return buf.str();		
		}
	};

	AmfIteratorPtr AmfArray::GetChildIterator()
	{
		AmfArrayIterator<AmfObjectArray,AmfObjectPtr>* pIt(new AmfArrayIterator< AmfObjectArray, AmfObjectPtr >);
		pIt->Set(this, &m_ObjAry);
		return pIt;
	}

	AmfIteratorPtr AmfExArrayInt::GetChildIterator()
	{
		AmfArrayIterator<StdIntArray,AmfObjectPtr>* pIt(new AmfArrayIterator< StdIntArray, AmfObjectPtr >);
		pIt->Set(this, &m_ObjAry);
		return pIt;
	}

	AmfIteratorPtr AmfExArrayFloat64::GetChildIterator()
	{
		AmfArrayIterator<StdDoubleArray,AmfObjectPtr>* pIt(new AmfArrayIterator< StdDoubleArray, AmfObjectPtr >);
		pIt->Set(this, &m_ObjAry);
		return pIt;
	}

	/************************************************************************/
	/* AmfAsObject
	/************************************************************************/
	class AmfHashMapIterator : public AmfIterator
	{
			AmfObjectPtr pObj;
		MapStrPtr* pMap;
		MapStrPtr::iterator it;

	public:
		void Set (AmfObject* obj, MapStrPtr* p_map)
		{
			pObj = obj;
			pMap = p_map;
			it = p_map->begin();
		}

		virtual void MoveFirst () { it = pMap->begin(); }
		virtual void MoveNext () { it++; }
		virtual bool Eof () { return (it == pMap->end()); }

		virtual AmfObjectPtr Get ()
		{
			if (it != pMap->end())
				return (*it).second;
			else
				throw HT::Except (HT_AMF_EOF, "Is Eof");
			//return AmfObject::GetNull();
			return NULL;
		}

		virtual wstring GetKey ()
		{
			if (it != pMap->end())
				return (*it).first;
			else
				throw HT::Except (HT_AMF_EOF, "Is Eof");
			return L"";
		}
	};

	AmfIteratorPtr AmfMap::GetChildIterator()
	{
		HPtr<AmfHashMapIterator> it = new AmfHashMapIterator;
		it->Set (this, &(GetValue()));
		return it;
	}

	AmfIteratorPtr AmfAsObject::GetChildIterator()
	{
		HPtr<AmfHashMapIterator> it = new AmfHashMapIterator;
		it->Set (this, &(GetValue()));
		return it;
	}

#define	COMPRESS_LEVER			9			//定义压缩的类型

	void AmfByteArray::Compress()
	{
		if(m_byteAry.size() <= 0)
			return;

		unsigned long iLen = compressBound(m_byteAry.size());
		StdByteArray buf;
		buf.resize(iLen);
		int ret = compress2(buf.pbegin(), &iLen, m_byteAry.pbegin(), m_byteAry.size(), COMPRESS_LEVER);
		if(ret < 0)
		{
			stringstream str;
			str << "AmfByteArray::Compress failed. errorcode: " << ret;
			throw HT::Except(HT_AMF_COMPRES, str.str().c_str());
		}

		m_byteAry.clear();
		m_byteAry.insert(m_byteAry.end(), buf.pbegin(), buf.pbegin() + iLen);
	}

	void AmfByteArray::Uncompress()
	{
		if(m_byteAry.size() <= 0)
			return;

		unsigned long iLen = m_byteAry.size() * 6;
		StdByteArray buf;
		buf.resize(iLen);
		int ret = uncompress(buf.pbegin(), &iLen, m_byteAry.pbegin(), m_byteAry.size());
		if(ret < 0)
		{
			stringstream str;
			str << "AmfByteArray::Uncompress failed. errorcode: " << ret;
			throw HT::Except(HT_AMF_UNCOMPRESS, str.str().c_str());
		}

		m_byteAry.clear();
		m_byteAry.insert(m_byteAry.end(), buf.pbegin(), buf.pbegin() + iLen);
	}
} //namespace Amf
